/**
 * File: PositionReadProcessor.java
 * Created by: mhaimel
 * Created on: 22 Jul 2009
 * CVS:  $Id: PositionReadProcessor.java,v 1.2 2009/10/09 15:10:12 mhaimel Exp $
 */
package uk.ac.ebi.curtain.processor.load.impl;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import javolution.util.FastMap;

import org.apache.commons.lang.NotImplementedException;

import uk.ac.ebi.curtain.processor.AbstractProcessor;
import uk.ac.ebi.curtain.processor.writer.BucketCollectionBean;
import uk.ac.ebi.curtain.service.IdentifierFilepositionIndex;
import uk.ac.ebi.curtain.util.FileIndexReader;
import uk.ac.ebi.curtain.util.FileIndexUtil;
import uk.ac.ebi.curtain.util.FileIndexReader.IndexFilter;
import uk.ac.ebi.curtain.util.FileIndexUtil.FileIndexEvent;
import uk.ac.ebi.curtain.utils.CurtainUncheckedException;
import uk.ac.ebi.curtain.utils.file.FileInfo;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;
import uk.ac.ebi.velvet.model.Strand;

/**
 * @author mhaimel
 *
 */
public class PositionReadProcessor extends AbstractProcessor<BucketCollectionBean, Serializable> {
	private static final Long DEFALT_SIZE = -1l;
	private Map<String, Long[]> posList = new FastMap<String, Long[]>();
	private int posSize = 2;
	private final CopyOnWriteArrayList<File> fileQueue = new CopyOnWriteArrayList<File>();
	
	public void addFile(File file){
		fileQueue.add(file);
	}
	
	public void setPositionSize(int size){
		this.posSize = size;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	protected Serializable buildReturnObject() {
		return "Finished";
	}
	
	public void reset(){
		posList.clear();
		posList = new FastMap<String, Long[]>();
	}
	
	public void register(Collection<String> readColl){
		for(String s : readColl){
			posList.put(s, getArray());
		}
	}
	
	public Long[] pos4Read(String read){
		return posList.get(read);
	}

	private Long[] getArray() {
		Long[] arr = new Long[posSize];
		for(int i = 0; i < posSize; ++i){
			arr[i] = DEFALT_SIZE;
		}
		return arr;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void process() {
		getLog().debug("Build read position index ...");
		FileIndexReader reader = null;
		FileIndexEvent handler = new MyHandler();
		for(File file : fileQueue.toArray(new File[0])){
			if(file.exists()){
				try{
					reader = getReader(file);			
					IndexFilter filter = new IndexFilter();
					filter.allowAll(false);
					filter.allowRead(true);
					reader.setEventHandler(handler, filter);
					FileIndexUtil.registerFiles(reader, getContext().getArguments(), getContext().getGlobalFileIndex());
					reader.open();
					reader.readAll();
				} catch (IOException e) {
					throw new CurtainUncheckedException("Problems reading position information",e);
				} finally{
					FileIO.closeQuietly(reader);
				}
			} else {
				getLog().warn("No read positions for " + file);
			}
		}
		getLog().debug("Finished read position index!");
	}

	private FileIndexReader getReader(File file) {
		IdentifierFilepositionIndex idxpos = getContext().getPositionIndex(file);
		idxpos.setReadOnly();
		return idxpos.getReader();
	}
	
	private void processRead(FileInfo fi, String key,Strand strand,Long locPos){
		Long[] posArr = posList.get(key);
		if(null != posArr){
			Long globPos = translate2GlobPos(fi,locPos);
			addPos(posArr,strand,globPos);
		}
	}
		
	private Long translate2GlobPos(FileInfo fi, Long locPos) {
		Long startPosition = getContext().getGlobalFileIndex().getStartPosition(fi);
		return startPosition+locPos;
	}

	private void addPos(Long[] posArr, Strand strand, Long pos) {
		if(null == strand 
				|| Strand.UNKOWN.equals(strand)
				|| Strand.FWD.equals(strand)	){
			posArr[0] = pos;
		} else {
			posArr[1] = pos;
		}
	}

	private class MyHandler implements FileIndexEvent{

		public void addContig(FileInfo fi, String key, Long pos) {
			throw new NotImplementedException("Not supported!");
		}

		public void addContigPosition(FileInfo fi, Long pos) {
			throw new NotImplementedException("Not supported!");
		}

		public void addFile(FileInfo fi, Integer category) {
		}

		public void addFileId(Integer fid, FileInfo fi) {
		}

		public void addInsertLength(Integer category, Integer insLen) {
		}

		public void addInsertLengthSd(Integer category, Integer sd) {
		}

		public void addRead(FileInfo fi, String key, Strand strand, Long pos) {
			processRead(fi,key,strand,pos);
		}

		public void addReadPosition(FileInfo fi, Strand strand, Long pos) {
			throw new NotImplementedException("Not supported!");
		}

		public void close() throws IOException {
		}

		@Override
		public void addCategory(Integer category, String id) { /* ignore */	}
		
	}
}
